﻿using System;

namespace Aeon.Emulator.Sound.FM.Operators
{
    /// <summary>
    /// Emulates the top cymbal OPL operator.
    /// </summary>
    internal class TopCymbal : StandardOperator
    {
        /// <summary>
        /// Initializes a new instance of the TopCymbal class.
        /// </summary>
        /// <param name="baseAddress">Base operator register address.</param>
        /// <param name="opl">FmSynthesizer instance which owns the operator.</param>
        protected TopCymbal(int baseAddress, FmSynthesizer opl)
            : base(baseAddress, opl)
        {
        }
        /// <summary>
        /// Initializes a new instance of the TopCymbal class.
        /// </summary>
        /// <param name="opl">FmSynthesizer instance which owns the operator.</param>
        public TopCymbal(FmSynthesizer opl)
            : base(0x15, opl)
        {
        }

        /// <summary>
        /// Returns the current output value of the operator.
        /// </summary>
        /// <param name="modulator">Modulation factor to apply to the output.</param>
        /// <returns>Current output value of the operator.</returns>
        public override double GetOperatorOutput(double modulator)
        {
            double highHatOperatorPhase = opl.RhythmHighHatOperator.Phase * PhaseMultipliers[opl.RhythmHighHatOperator.Multiplier];
            return GetOperatorOutput(modulator, highHatOperatorPhase);
        }
        protected double GetOperatorOutput(double modulator, double externalPhase)
        {
            double envelopeInDB = this.GetEnvelope();
            this.Envelope = Math.Pow(10, envelopeInDB / 10.0);

            RecalculatePhase();

            var waveform = this.SelectedWaveform;

            double carrierPhase = (8 * this.Phase) % 1;
            double modulatorPhase = externalPhase;
            double modulatorOutput = GetOutput(0, modulatorPhase, waveform);
            double carrierOutput = GetOutput(modulatorOutput, carrierPhase, waveform);

            int cycles = 4;
            if((carrierPhase * cycles) % cycles > 0.1)
                carrierOutput = 0;

            return carrierOutput * 2;
        }
    }
}
